package com.njxxted.activiti.modules.process.defintion.service.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.njxxted.activiti.common.constant.Constant;
import com.njxxted.activiti.common.exception.CustomerException;
import com.njxxted.activiti.common.response.ResponseVo;
import com.njxxted.activiti.common.util.BpmnBuilderUtil;
import com.njxxted.activiti.common.util.JsonUtils;
import com.njxxted.activiti.common.util.StringUtils;
import com.njxxted.activiti.common.util.WorkflowUtils;
import com.njxxted.activiti.modules.base.service.BaseService;
import com.njxxted.activiti.modules.process.cmd.BpmnDefinitionCmd;
import com.njxxted.activiti.modules.process.cmd.ProcessInstanceCmd;
import com.njxxted.activiti.modules.process.defintion.dao.ActDefinitionDao;
import com.njxxted.activiti.modules.process.defintion.entity.ActNodeConfigEntity;
import com.njxxted.activiti.modules.process.defintion.service.IActDefinitionService;
import com.njxxted.activiti.modules.process.extend.dao.ExtendActHistoryDao;
import com.njxxted.activiti.modules.process.extend.entity.ExtendActHistoryEntity;
import com.njxxted.activiti.modules.process.extend.entity.ExtendActInstanceEntity;
import com.njxxted.activiti.modules.process.extend.service.ExtendActInstanceService;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Model;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 * 描述：流程定义 service
 * <p>
 * 作者：Ostrich Hu
 * 时间：2019/9/3 15:01 星期二
 */
@Service
public class IActDefinitionServiceImpl extends BaseService implements IActDefinitionService {

    private static final String DUE_DATE = "dueDate";
    private static final String JUMP_TYPE = "jumpType";
    private static final String NODE_BTN = "nodeBtn";

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ExtendActInstanceService extendActInstanceService;
    @Resource
    private ExtendActHistoryDao extendActHistoryDao;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private HistoryService historyService;
    @Resource
    private IdentityService identityService;
    @Resource
    private ActDefinitionDao actDefinitionDao;
    @Resource
    ObjectMapper objectMapper;

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public ResponseVo processDefinitionSettings(HttpServletRequest request) {
        try {
            List<BpmnDefinitionCmd> bpmnDefinitionCmds = BpmnBuilderUtil.buildBpmnDefinitionCmd(request);
            Model model = repositoryService.getModel(bpmnDefinitionCmds.get(0).getModelId());
            byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
            //读取editorSource
            JsonNode processJsonGlobal = objectMapper.readTree(modelEditorSource);
            JsonNode processChildShapes = processJsonGlobal.findValue("childShapes");
            ObjectNode propertiesGlobal = (ObjectNode) processJsonGlobal.findValue("properties");
            //1.全局配置
            //1.1 设置流程执行监听器
            HashMap<String, Map[]> mapExeListeners = Maps.newHashMap();
            Map<String, String> mapStartExeListen = Maps.newHashMap();
            mapStartExeListen.put("event", "start");
            mapStartExeListen.put("implementation", Constant.Flow.PROCESS_LISTENER_START);
            mapStartExeListen.put("className", Constant.Flow.PROCESS_LISTENER_START);
            mapStartExeListen.put("expression", "");
            mapStartExeListen.put("delegateExpression", "");
            Map<String, String> mapEndExeListen = Maps.newHashMap();
            mapEndExeListen.put("event", "end");
            mapEndExeListen.put("implementation", Constant.Flow.PROCESS_LISTENER_END);
            mapEndExeListen.put("className", Constant.Flow.PROCESS_LISTENER_END);
            mapEndExeListen.put("expression", "");
            mapEndExeListen.put("delegateExpression", "");
            Map[] exeMaps = {mapStartExeListen, mapEndExeListen};
            mapExeListeners.put("executionListeners", exeMaps);
            propertiesGlobal.put("executionlisteners", JsonUtils.beanToJson(mapExeListeners));

            //2.局部配置
            Set<ActNodeConfigEntity> actNodeConfigEntitys = Sets.newHashSet();
            processChildShapes.forEach(childJson -> {
                String resourceId = childJson.findValue("resourceId").asText();
                String overrideId = childJson.findValue("properties").findValue("overrideid").asText().trim();
                ObjectNode properties = (ObjectNode) childJson.findValue("properties");
                JsonNode stencil = childJson.findValue("stencil");
                JsonNode childShapes = childJson.findValue("childShapes");
                JsonNode outgoing = childJson.findValue("outgoing");
                String stencilValue = stencil.findValue("id").asText();

                String nodeId = StringUtils.isNotEmpty(overrideId) ? overrideId : resourceId;
                bpmnDefinitionCmds.parallelStream().forEachOrdered(bpmnDefinitionCmd -> {

                    String nodeId_ = bpmnDefinitionCmd.getNodeId();
                    List<Map> nodeUser = bpmnDefinitionCmd.getNodeUser();
                    List<Map> nodeForm = bpmnDefinitionCmd.getNodeForm();
                    List<Map> nodeGate = bpmnDefinitionCmd.getNodeGate();
                    String nodeBtn = bpmnDefinitionCmd.getNodeBtn();
                    String nodeType = bpmnDefinitionCmd.getNodeType();
                    String key = bpmnDefinitionCmd.getKey();
                    String modelId = bpmnDefinitionCmd.getModelId();
                    String nodeDueDate = bpmnDefinitionCmd.getNodeDueDate();
                    String nodeDueDateType = bpmnDefinitionCmd.getNodeDueDateType();
                    List<Map> nodeCopyUser = bpmnDefinitionCmd.getNodeCopyUser();
                    String nodeJumpType = bpmnDefinitionCmd.getNodeJumpType();

                    if (Objects.equals(nodeId_, nodeId)) {
                        //2.1 用户任务节点配置
                        //2.1.1 设置表单
                        if (nodeForm != null && nodeForm.size() > 0 && stencilValue.equalsIgnoreCase(Constant.Flow.USER_TASK)) {
                            List<String> formKeyList = Lists.newArrayList();
                            nodeForm.forEach(form -> {
                                String formKey = String.valueOf(form.get("formKey"));
                                String formType = String.valueOf(form.get("formType"));
                                if (StringUtils.isNotEmpty(formKey) && StringUtils.isNotEmpty(formType)) {
                                    ActNodeConfigEntity actNodeConfigEntity = new ActNodeConfigEntity();
                                    actNodeConfigEntity.setKey(key);
                                    actNodeConfigEntity.setModelId(modelId);
                                    actNodeConfigEntity.setNodeId(nodeId_);
                                    actNodeConfigEntity.setConfigType(formType);
                                    actNodeConfigEntity.setConfigValue(formKey);
                                    actNodeConfigEntity.setAddDate(new Date());
                                    actNodeConfigEntitys.add(actNodeConfigEntity);
                                    formKeyList.add(formKey);
                                }
                            });
                            if (formKeyList.size() > 0) {
                                properties.put("formkeydefinition", String.join(",", formKeyList));
                            }
                        } else {
                            properties.remove("formkeydefinition");
                        }
                        //2.1.2 设置人员
                        if (nodeUser != null && nodeUser.size() > 0 && stencilValue.equalsIgnoreCase(Constant.Flow.USER_TASK)) {
                            List<Map<String, String>> candidateUsers = Lists.newArrayList();
                            List<Map<String, String>> candidateGroups = Lists.newArrayList();
                            nodeUser.forEach(user -> {
                                String type = String.valueOf(user.get("type"));
                                Map<String, String> map = Maps.newHashMap();
                                String id = String.valueOf(user.get("id"));
                                if (StringUtils.isNotEmpty(id)) {
                                    String[] split = id.split("/");
                                    map.put("value", split[split.length - 1]);
                                    switch (type) {
                                        case "user":
                                            candidateUsers.add(map);
                                            break;
                                        case "depart":
                                        case "role":
                                            candidateGroups.add(map);
                                            break;
                                    }
                                }
                                ActNodeConfigEntity actNodeConfigEntity = new ActNodeConfigEntity();
                                actNodeConfigEntity.setKey(key);
                                actNodeConfigEntity.setModelId(modelId);
                                actNodeConfigEntity.setNodeId(nodeId_);
                                actNodeConfigEntity.setConfigType("assign:" + type);
                                actNodeConfigEntity.setConfigValue(String.valueOf(user.get("id")));
                                actNodeConfigEntity.setOtherValue(String.valueOf(user.get("logic")));
                                actNodeConfigEntity.setAddDate(new Date(Long.parseLong(user.get("time").toString())));
                                actNodeConfigEntitys.add(actNodeConfigEntity);
                            });

                            Map<String, Object> assignment = Maps.newHashMap();
                            if (candidateUsers.size() > 0) {
                                assignment.put(Constant.Flow.CANDIDATE_USER, candidateUsers);
                            }
                            if (candidateGroups.size() > 0) {
                                assignment.put(Constant.Flow.CANDIDATE_GROUP, candidateGroups);
                            }
                            Map<String, Object> userTaskAssignment = Maps.newHashMap();
                            userTaskAssignment.put("assignment", assignment);
                            properties.put("usertaskassignment", JSON.toJSONString(userTaskAssignment));
                        } else {
                            properties.remove("usertaskassignment");
                        }

                        //2.1.3 设置节点抄送人员
                        if (nodeCopyUser != null && nodeCopyUser.size() > 0 && stencilValue.equalsIgnoreCase(Constant.Flow.USER_TASK)) {
                            nodeCopyUser.forEach(user -> {
                                ActNodeConfigEntity actNodeConfigEntity = new ActNodeConfigEntity();
                                actNodeConfigEntity.setKey(key);
                                actNodeConfigEntity.setModelId(modelId);
                                actNodeConfigEntity.setNodeId(nodeId_);
                                actNodeConfigEntity.setConfigType("copy:" + user.get("type"));
                                actNodeConfigEntity.setConfigValue(String.valueOf(user.get("id")));
                                actNodeConfigEntity.setOtherValue(String.valueOf(user.get("logic")));
                                actNodeConfigEntity.setAddDate(new Date());
                                actNodeConfigEntitys.add(actNodeConfigEntity);
                            });

                        }

                        //2.2 配置节点按钮
                        if (StringUtils.isNotEmpty(nodeBtn) && stencilValue.equalsIgnoreCase(Constant.Flow.USER_TASK)) {
                            ActNodeConfigEntity actNodeConfigEntity = new ActNodeConfigEntity();
                            actNodeConfigEntity.setKey(key);
                            actNodeConfigEntity.setModelId(modelId);
                            actNodeConfigEntity.setNodeId(nodeId_);
                            actNodeConfigEntity.setConfigType(NODE_BTN);
                            actNodeConfigEntity.setConfigValue(nodeBtn);
                            actNodeConfigEntity.setAddDate(new Date());
                            actNodeConfigEntitys.add(actNodeConfigEntity);
                        }

                        //2.3 网关（网关顺序流）配置
                        if (nodeGate != null && nodeGate.size() > 0 && stencilValue.equalsIgnoreCase(Constant.Flow.EXCLUSIVE_GATEWAY)) {
                            //2.3.1 给网关的输出顺序流设置条件
                            nodeGate.forEach(gate -> {
                                String gateWayId = String.valueOf(gate.get("gateWayId"));
                                String elExpression = String.valueOf(gate.get("elExpression"));
                                String sequenceId = String.valueOf(gate.get("sequenceId"));
                                //遍历所有节点
                                processChildShapes.forEach(childShape -> {
                                    String targetResourceId = childShape.findValue("resourceId").asText();
                                    String childOverrideId = childShape.findValue("properties").findValue("overrideid").asText().trim();
                                    if (sequenceId.equals(targetResourceId) || sequenceId.equals(childOverrideId)) {
                                        ObjectNode seqProperties = (ObjectNode) childShape.findValue("properties");
                                        seqProperties.put("conditionsequenceflow", elExpression);
                                        logger.debug("targetResourceId={}={}", elExpression, targetResourceId);

                                        ActNodeConfigEntity actNodeConfigEntity = new ActNodeConfigEntity();
                                        actNodeConfigEntity.setKey(key);
                                        actNodeConfigEntity.setModelId(modelId);
                                        actNodeConfigEntity.setNodeId(gateWayId);
                                        actNodeConfigEntity.setConfigType("gateWay");
                                        actNodeConfigEntity.setConfigValue(elExpression);
                                        actNodeConfigEntity.setOtherValue(sequenceId);
                                        actNodeConfigEntity.setAddDate(new Date());
                                        actNodeConfigEntitys.add(actNodeConfigEntity);
                                    }
                                });
                            });
                        }

                        //2.4 设置到期时间
                        if (StringUtils.isNotEmpty(nodeDueDate) && stencilValue.equalsIgnoreCase(Constant.Flow.USER_TASK)) {
//                            properties.put("duedatedefinition", nodeDueDate);
                            ActNodeConfigEntity actNodeConfigEntity = new ActNodeConfigEntity();
                            actNodeConfigEntity.setKey(key);
                            actNodeConfigEntity.setModelId(modelId);
                            actNodeConfigEntity.setNodeId(nodeId_);
                            actNodeConfigEntity.setConfigType(DUE_DATE);
                            actNodeConfigEntity.setConfigValue(nodeDueDate);
                            actNodeConfigEntity.setOtherValue(nodeDueDateType);
                            actNodeConfigEntity.setAddDate(new Date());
                            actNodeConfigEntitys.add(actNodeConfigEntity);
                        }

                        //2.5 设置跳转类型
                        if (StringUtils.isNotEmpty(nodeJumpType) && stencilValue.equalsIgnoreCase(Constant.Flow.USER_TASK)) {
                            ActNodeConfigEntity actNodeConfigEntity = new ActNodeConfigEntity();
                            actNodeConfigEntity.setKey(key);
                            actNodeConfigEntity.setModelId(modelId);
                            actNodeConfigEntity.setNodeId(nodeId_);
                            actNodeConfigEntity.setConfigType(JUMP_TYPE);
                            actNodeConfigEntity.setConfigValue(nodeJumpType);
                            actNodeConfigEntity.setAddDate(new Date());
                            actNodeConfigEntitys.add(actNodeConfigEntity);
                        }

                        //2.6 设置任务执行监听器
                        if (stencilValue.equalsIgnoreCase(Constant.Flow.USER_TASK)) {
//                            HashMap<String, Map[]> mapListeners = Maps.newHashMap();
//                            Map<String, String> mapListen = Maps.newHashMap();
//                            mapListen.put("event", "start");
//                            mapListen.put("implementation", "");
//                            mapListen.put("className", "");
//                            mapListen.put("expression", "");
//                            mapListen.put("delegateExpression", "");
//                            Map[] maps = {mapListen};
//                            mapListeners.put("executionListeners", maps);
//                            ObjectNode seqProperties = (ObjectNode) childJson.findValue("properties");
//                            seqProperties.put("executionlisteners", JsonUtils.beanToJson(mapListeners));
                        }

                        //2.7 设置任务监听器（create：创建、complete:完成、assignment:办理时、delete:删除）
                        if (stencilValue.equalsIgnoreCase(Constant.Flow.USER_TASK)) {
                            HashMap<String, Map[]> mapTaskListeners = Maps.newHashMap();
                            Map<String, String> mapCreateListen = Maps.newHashMap();
                            mapCreateListen.put("event", "create");
                            mapCreateListen.put("implementation", Constant.Flow.TASK_LISTENER_CREATE);
                            mapCreateListen.put("className", Constant.Flow.TASK_LISTENER_CREATE);
                            mapCreateListen.put("expression", "");
                            mapCreateListen.put("delegateExpression", "");
                            Map<String, String> mapFinishListen = Maps.newHashMap();
                            mapFinishListen.put("event", "complete");
                            mapFinishListen.put("implementation", Constant.Flow.TASK_LISTENER_FINISH);
                            mapFinishListen.put("className", Constant.Flow.TASK_LISTENER_FINISH);
                            mapFinishListen.put("expression", "");
                            mapFinishListen.put("delegateExpression", "");
                            Map[] maps = {mapCreateListen, mapFinishListen};
                            mapTaskListeners.put("taskListeners", maps);
                            ObjectNode seqProperties = (ObjectNode) childJson.findValue("properties");
                            seqProperties.put("tasklisteners", JsonUtils.beanToJson(mapTaskListeners));
                        }
                    }
                });
            });
            String replace = processJsonGlobal.toString().replace("\"{", "{")
                    .replace("\\", "").replace("}}\"", "}}")
                    .replace("}]}\"", "}]}");
            System.out.println(replace);
            repositoryService.addModelEditorSource(model.getId(), replace.getBytes(StandardCharsets.UTF_8));
            //将配置信息插入自定义扩展的节点配置表
            actDefinitionDao.delete(bpmnDefinitionCmds.get(0).getKey(), null, null);
            actDefinitionDao.insertBatch(actNodeConfigEntitys);
            return ResponseVo.ok("设置流程定义成功");
        } catch (IOException e) {
            throw new CustomerException("设置流程定义失败", e);
        }

    }

    @Override
    public void getDefinitionImage(String modelId, HttpServletResponse response) throws IOException {
        //读取editorSource
        Model model = repositoryService.createModelQuery().modelId(modelId).singleResult();
        byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
        JsonNode jsonNode = objectMapper.readTree(modelEditorSource);
        //转换editorSource为bpmnModel
        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
        try (OutputStream os = response.getOutputStream(); InputStream resourceAsStream = WorkflowUtils.getFlowImage(bpmnModel)) {
            byte[] b = new byte[1024];
            int len = -1;
            while (((len = resourceAsStream.read(b, 0, 1024)) != -1)) {
                response.getOutputStream().write(b, 0, len);
            }
            //设置输出文件的信息
            response.setCharacterEncoding("UTF-8");
            response.setContentType("image/png;charset=utf-8");
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
        } catch (IOException e) {
            throw new CustomerException("获取资源图片异常", e);
        }
    }

    @Transactional(readOnly = true)
    @Override
    public List<Map<String, Object>> getProcessDefinitionSettings(ActNodeConfigEntity param) {
        List<ActNodeConfigEntity> configEntities = actDefinitionDao.getProcessDefinitionSettings(param);
        List<Map<String, Object>> list = Lists.newCopyOnWriteArrayList();
        //1.根据节点id分组
        Map<String, List<ActNodeConfigEntity>> collectByNode = configEntities.parallelStream()
                .collect(Collectors.groupingBy(ActNodeConfigEntity::getNodeId));
        //2.遍历每个节点
        Set<String> keySet = collectByNode.keySet();
        keySet.parallelStream().forEachOrdered(nodeId -> {
            Map<String, Object> nodeMap = Maps.newHashMap();
            nodeMap.put("modelId", param.getModelId());
            nodeMap.put("key", param.getKey());
            nodeMap.put("nodeId", nodeId);
            nodeMap.put("nodeType", "");

            //3. 取出每个节点的配置信息，并进行数据格式组装
            List<ActNodeConfigEntity> nodeConfigEntities = collectByNode.get(nodeId);
            Set<Map<String, String>> nodeUser = new CopyOnWriteArraySet<>();
            Set<Map<String, String>> nodeCopyUser = new CopyOnWriteArraySet<>();
            Set<Map<String, String>> nodeForm = new CopyOnWriteArraySet<>();
            Set<Map<String, String>> nodeGate = new CopyOnWriteArraySet<>();
            Map<String, Object> dueDateMap = Maps.newHashMap();
            //排序
            nodeConfigEntities.sort(Comparator.comparing(ActNodeConfigEntity::getAddDate));
            nodeConfigEntities.parallelStream().forEachOrdered(nodeConfigVal -> {
                HashMap<String, String> mapVal = Maps.newHashMap();
                if (nodeConfigVal.getConfigType().contains("assign")) {
                    mapVal.put("type", nodeConfigVal.getConfigType().split(":")[1]);
                    mapVal.put("id", nodeConfigVal.getConfigValue());
                    mapVal.put("logic", nodeConfigVal.getOtherValue());
                    mapVal.put("time", String.valueOf(nodeConfigVal.getAddDate().getTime()));
                    nodeUser.add(mapVal);
                }

                if (nodeConfigVal.getConfigType().contains("copy")) {
                    mapVal.put("type", nodeConfigVal.getConfigType().split(":")[1]);
                    mapVal.put("id", nodeConfigVal.getConfigValue());
                    mapVal.put("logic", nodeConfigVal.getOtherValue());
                    mapVal.put("time", String.valueOf(nodeConfigVal.getAddDate().getTime()));
                    nodeCopyUser.add(mapVal);
                }

                if (nodeConfigVal.getConfigType().contains("form")) {
                    mapVal.put("formKey", nodeConfigVal.getConfigValue());
                    mapVal.put("formType", nodeConfigVal.getConfigType());
                    nodeForm.add(mapVal);
                }

                if (nodeConfigVal.getConfigType().contains("gateWay")) {
                    mapVal.put("sequenceId", nodeConfigVal.getOtherValue());
                    mapVal.put("gateWayId", nodeConfigVal.getNodeId());
                    mapVal.put("elExpression", nodeConfigVal.getConfigValue());
                    nodeGate.add(mapVal);
                }
            });

            List<ActNodeConfigEntity> nodeBtnCollect = nodeConfigEntities.parallelStream()
                    .filter(node -> nodeId.equals(node.getNodeId()) && node.getConfigType().equals(NODE_BTN))
                    .collect(Collectors.toList());
            List<ActNodeConfigEntity> dueDateCollect = nodeConfigEntities.parallelStream()
                    .filter(node -> nodeId.equals(node.getNodeId()) && node.getConfigType().equals(DUE_DATE))
                    .collect(Collectors.toList());
            List<ActNodeConfigEntity> jumpTypeCollect = nodeConfigEntities.parallelStream()
                    .filter(node -> nodeId.equals(node.getNodeId()) && node.getConfigType().equals(JUMP_TYPE))
                    .collect(Collectors.toList());

            dueDateMap.put("timeLimitType", dueDateCollect.size() > 0 ? dueDateCollect.get(0).getOtherValue() : "0");
            dueDateMap.put("dateNum", dueDateCollect.size() > 0 ? dueDateCollect.get(0).getConfigValue() : "");

            nodeMap.put("nodeBtn", nodeBtnCollect.size() > 0 ? nodeBtnCollect.get(0).getConfigValue() : "");
            nodeMap.put("nodeDueDate", dueDateMap);
            nodeMap.put("nodeJumpType", jumpTypeCollect.size() > 0 ? jumpTypeCollect.get(0).getConfigValue() : "");
            nodeMap.put("nodeCopyUser", nodeCopyUser);
            nodeMap.put("nodeUser", nodeUser);
            nodeMap.put("nodeForm", nodeForm);
            nodeMap.put("nodeGate", nodeGate);
            list.add(nodeMap);
        });

        return list;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public ExtendActInstanceEntity startInstanceByDefinition(HttpServletRequest request) {
        ProcessInstanceCmd cmd = BpmnBuilderUtil.buildProcessInstanceCmd(request);
        boolean isDraft = Constant.Flow.TASK_DRAFT.equalsIgnoreCase(cmd.getIsDraft());
        ExtendActInstanceEntity extendActEntity;
        try {
            identityService.setAuthenticatedUserId(cmd.getStartUserId());
            ProcessInstance instance = runtimeService.startProcessInstanceByKey(cmd.getKey(), cmd.getBusinessId(), cmd.getVariables());
            String instanceId = instance.getId();
            runtimeService.setProcessInstanceName(instanceId, cmd.getExtInstanceName());
            logger.debug("业务id:{}流程实例id:{}流程定义id:{}", cmd.getBusinessId(), instanceId, instance.getProcessDefinitionId());
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
            //业务数据和流程引擎发起流程成功之后，向自定义流程实例扩展表中插入数据
            extendActEntity = new ExtendActInstanceEntity(processInstance);
            extendActEntity.setStartUserName(cmd.getStartUserName());
            extendActEntity.setStartUserId(cmd.getStartUserId());
            extendActEntity.setStatus(isDraft ? Constant.Flow.TASK_DRAFT : Constant.Flow.TASK_AGREE);
            extendActEntity.setName(processInstance.getName());
            extendActInstanceService.save(extendActEntity);
            //插入自定义的流程历史
            HistoricTaskInstance taskHis = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceId).singleResult();
            ExtendActHistoryEntity historyEntity = new ExtendActHistoryEntity(taskHis);
            historyEntity.setOperateType(isDraft ? Constant.Flow.TASK_DRAFT : Constant.Flow.TASK_AGREE);
            historyEntity.setId(StringUtils.uuidGenerator());
            historyEntity.setProcessDefKey(cmd.getKey());
            historyEntity.setOperateUserId(cmd.getStartUserId());
            historyEntity.setBusinessId(cmd.getBusinessId());
            historyEntity.setOperateComment("发起流程");
            extendActHistoryDao.save(historyEntity);
        } finally {
            identityService.setAuthenticatedUserId(null);
        }
        return extendActEntity;
    }

    @Override
    public ExtendActInstanceEntity updInstanceByDefinition(HttpServletRequest request) {
        ProcessInstanceCmd cmd = BpmnBuilderUtil.buildProcessInstanceCmd(request);
        boolean isDraft = Constant.Flow.TASK_DRAFT.equalsIgnoreCase(cmd.getIsDraft());
        ExtendActInstanceEntity extendActEntity;
        logger.debug("业务id：{}流程实例id：{}", cmd.getBusinessId(), cmd.getInstanceId());
        //修改自定义流程实例数据
        extendActEntity = new ExtendActInstanceEntity();
        extendActEntity.setStatus(isDraft ? Constant.Flow.TASK_DRAFT : Constant.Flow.TASK_AGREE);
        extendActEntity.setName(cmd.getExtInstanceName());
        extendActEntity.setStartUserId(cmd.getStartUserId());
        extendActEntity.setStartUserName(cmd.getStartUserName());
        extendActEntity.setBusinessId(cmd.getBusinessId());
        extendActEntity.setInstanceId(cmd.getInstanceId());
        extendActEntity.setRecentlyDoTime(new Date());
        extendActInstanceService.update(extendActEntity);
        //修改自定义的流程历史
        ExtendActHistoryEntity historyEntity = new ExtendActHistoryEntity();
        historyEntity.setProcessInstanceId(cmd.getInstanceId());
        historyEntity.setBusinessId(cmd.getBusinessId());
        historyEntity.setTaskDefKey(cmd.getTaskDefKey());
        historyEntity.setOperateType(isDraft ? Constant.Flow.TASK_DRAFT : Constant.Flow.TASK_AGREE);
        extendActHistoryDao.update(historyEntity);
        return extendActEntity;
    }

    @Override
    public void getFlowExecutionRouteImage(String instanceId, HttpServletResponse response) {
        if (StringUtils.isEmpty(instanceId)) {
            throw new CustomerException("流程实例id 不能为空");
        }
        //1. 设置输出文件的信息
        response.setCharacterEncoding("UTF-8");
        response.setContentType("image/png;charset=utf-8");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-store");
        response.setDateHeader("Expires", 0);
        //2. 获取输入流
        try (OutputStream os = response.getOutputStream();
             InputStream resourceAsStream = WorkflowUtils.getFlowExecutionRouteImage(instanceId)) {
            byte[] b = new byte[1024];
            int len = -1;
            while (((len = resourceAsStream.read(b, 0, 1024)) != -1)) {
                response.getOutputStream().write(b, 0, len);
            }
        } catch (IOException e) {
            throw new CustomerException("获取流程执行路径图片失败", e);
        }
    }

}
